package top.lingkang.finalgateway.admin.terminal;

import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.noear.snack.ONode;
import org.noear.socketd.transport.core.Message;
import org.noear.socketd.transport.core.Session;
import org.noear.socketd.transport.core.entity.EntityDefault;
import org.noear.socketd.transport.core.listener.SimpleListener;
import org.noear.solon.Solon;
import top.lingkang.finalgateway.admin.constants.LogType;
import top.lingkang.finalgateway.admin.mapper.ActionLogMapper;
import top.lingkang.finalgateway.utils.HttpUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lingkang
 * @create by 2024/3/19 17:08
 */
@Slf4j
public class WsSimpleListener extends SimpleListener {
    private static final OkHttpClient client = new OkHttpClient.Builder().build();
    public static final Map<String, TerminalHandler> terminalMap = new HashMap<>();
    private ActionLogMapper actionLogMapper;


    public WsSimpleListener() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            for (Map.Entry<String, TerminalHandler> entry : terminalMap.entrySet())
                entry.getValue().onTerminalClose();
            log.info("关闭所有ws，关闭数量：{}", terminalMap.size());
        }));
    }

    @Override
    public void onOpen(Session session) throws IOException {
        if (actionLogMapper == null)
            actionLogMapper = Solon.context().getBean(ActionLogMapper.class);
        String token = session.param("token");
        if (token == null) {
            log.warn("无token的连接，关闭会话：{}", session.sessionId());
            session.close();
            actionLogMapper.addLog(LogType.terminal_conn_fail, HttpUtils.getIpv4Address(session.remoteAddress()), "token无效");
            return;
        }
        Request request = new Request.Builder()
                .url("http://127.0.0.1:" + System.getProperty("server.port", "19595") + "/api/user/isLogin")
                .build();
        // 将Cookie添加到请求中
        Request newRequest = request.newBuilder()
                .addHeader("Cookie", "SOLONID=" + token)
                .build();

        Call call = client.newCall(newRequest);
        try (Response response = call.execute()) {
            String rss = response.body().string();
            if (!rss.contains("ok")) {
                session.close();
                log.info("无效的token: {} - res={}", token, rss);
                actionLogMapper.addLog(LogType.terminal_conn_fail, HttpUtils.getIpv4Address(session.remoteAddress()), "token无效");
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("连接, token={} sessionId={}", token, session.sessionId());
        actionLogMapper.addLog(LogType.terminal_conn_success, HttpUtils.getIpv4Address(session.remoteAddress()), "token=" + token);
    }

    @Override
    public void onMessage(Session session, Message message) throws IOException {
        String type = message.meta("type");
        if (type != null) {
            String data = message.entity().dataAsString();
            if ("cmd".equals(type)) {
                TerminalHandler terminal = terminalMap.get(session.sessionId());
                terminal.command(data);
            } else if ("resize".equals(type)) {
                ONode node = ONode.loadStr(data);
                TerminalHandler terminal = terminalMap.get(session.sessionId());
                terminal.resize(node.get("columns").getString(), node.get("rows").getString());
            } else if ("init".equals(type)) {
                ONode node = ONode.loadStr(data);
                TerminalHandler terminal = new TerminalHandler(
                        session,
                        node.select("$.columns").getString(),
                        node.select("$.rows").getString());
                terminalMap.put(session.sessionId(), terminal);
            } else if ("ping".equals(type)) {
                EntityDefault entityDefault = new EntityDefault();
                entityDefault.dataSet(message.data());
                entityDefault.metaPut("type", "pong");
                session.send("/", entityDefault);
            } else if ("close".equals(type)) {
                log.info("前端主动关闭会话");
                session.close();
            } else {
                log.warn("不支持的指令：" + message.data());
            }
        }
    }

    @Override
    public void onClose(Session session) {
        TerminalHandler terminal = terminalMap.remove(session.sessionId());
        if (terminal != null)
            terminal.onTerminalClose();
        log.info("断开连接 " + session.sessionId());
    }

    @Override
    public void onError(Session session, Throwable error) {
        log.warn("onError {}", session.sessionId(), error);
    }
}
